# -*- coding:utf-8 -*-

import asyncmongo
import tornado.gen

from bson.objectid     import ObjectId

from asyncmongo.errors import IntegrityError

from utils.lib_re      import between_quota, between_underline_dollar

from loog.mylog        import flogger as logger


db_pools = None

def initMongoDb(host='localhost', port=27017, pool_id='FOTA', dbuser='', dbpass=''):
    """ 初始化mongodb
    """
    global db_pools
    db_pools = asyncmongo.Client(pool_id=pool_id,
                                 host=host,
                                 port=port,
                                 dbuser=dbuser,
                                 dbpass=dbpass,
                                 dbname='admin',
                                 maxcached=500,
                                 maxconnections=1500)

def get_db_conn(db, collection):
    db = db_pools.connection(collection, db)
    return db

@tornado.gen.engine
def insert(db, collection, spec, callback=None):
    """ 添加 insert
    """
    db = get_db_conn(db, collection)
    _, e = yield tornado.gen.Task(db.insert, spec)

    if e.get('error'):
        # 唯一索引 重复的值
        if isinstance(e.get('error'), IntegrityError):
            msg = e['error'].msg
            name  = between_underline_dollar(msg)[0]
            value = between_quota(msg)[0]
            raise IntegrityError({'name':name,'value':value})
            callback(False)

        raise Exception(e)
        callback(False)

    callback(True)

@tornado.gen.engine
def update(db, collection, spec, fields, upsert=False, manipulate=False,
            safe=True, multi=False, callback=None):
    """ 更新 update
    """
    db = get_db_conn(db, collection)
    if spec and '_id' in spec:
        spec['_id'] = ObjectId(spec['_id'])

    _, e = yield tornado.gen.Task(
                db.update, spec, {'$set': fields},
                upsert=upsert,manipulate=manipulate,safe=safe,multi=multi)

    if e.get('error'):
        # 唯一索引 重复的值
        if isinstance(e.get('error'), IntegrityError):
            msg = e['error'].msg
            name  = between_underline_dollar(msg)[0]
            value = between_quota(msg)[0]
            raise IntegrityError({'name':name,'value':value})
            callback(False)

        raise Exception(e)
        callback(False)

    callback(True)


@tornado.gen.engine
def inc(db, collection, spec, inc_dict, upsert=False, manipulate=False,
            safe=True, multi=False, callback=None):
    """ 更新 - 自增 """

    db = get_db_conn(db, collection)
    if spec and '_id' in spec:
        spec['_id'] = ObjectId(spec['_id'])

    _, e = yield tornado.gen.Task(
                db.update, spec, inc_dict,
                upsert=upsert,manipulate=manipulate,safe=safe,multi=multi)

    if e.get('error'):
        raise Exception(e)
        callback(False)

    callback(True)


@tornado.gen.engine
def find_one(db, collection, spec, fields=None, callback=None):
    """ 查询 find_one
    """
    db = get_db_conn(db, collection)
    if spec and '_id' in spec:
        spec['_id'] = ObjectId(spec['_id'])
    d, e = yield tornado.gen.Task(db.find_one, spec, fields=fields)
    if e.get('error'):
        raise Exception(e)
    data = d[0]
    if data:
        data['_id'] = str(data['_id'])
        callback(data)
    else:
        callback(None)

@tornado.gen.engine
def find_all(
        db,collection,spec=None,fields=None,
        skip=0,limit=0,sort=None,callback=None):
    """ 查询 find_all """

    db = get_db_conn(db, collection)

    if spec and '_id' in spec:
        spec['_id'] = ObjectId(spec['_id'])

    d, e = yield tornado.gen.Task(
                    db.find,spec,fields=fields,skip=skip,
                    limit=limit,sort=sort)
    if e.get('error'): raise Exception(e)

    data = d[0]
    return_datas = []
    for item in data:
        item['_id'] = str(item['_id'])
        return_datas.append(item)
    callback(return_datas)


@tornado.gen.engine
def count(db, collection, sort, spec=None, callback=None):
    """ 查询指定条件的数据量

    注意:
        asyncmongo 没有提供 count 方法
        这里的解决方式是，全部对象查出来再使用 len() 来获取长度
        这种方式效率会非常低

        sort 是每个find操作的必填字段，因为这样才能查出所有数据
    """

    db = get_db_conn(db, collection)

    if spec and '_id' in spec:
        spec['_id'] = ObjectId(spec['_id'])

    d, e = yield tornado.gen.Task(db.find, spec, sort=sort)

    if e.get('error'): raise Exception(e)

    count = len(d[0])
    callback(count)


@tornado.gen.engine
def distinct(db, collection, key, spec=None, callback=None):
    """ distinct查询
    """
    command = {
               'distinct':  collection,
               'key':       key,
               'query':     spec
               }
    d, e = yield tornado.gen.Task(db_pools.connection("$cmd", db).find_one, command,
                                  _must_use_master=True, _is_command=True)
    if e.get('error'):
        raise Exception(e)
    data = d[0].get('values')
    callback(data)

@tornado.gen.engine
def remove(db, collection, spec=None, callback=None):
    """ 删除数据
    """
    db = get_db_conn(db, collection)
    if spec and '_id' in spec:
        spec['_id'] = ObjectId(spec['_id'])
    _, e = yield tornado.gen.Task(db.remove, spec)
    if e.get('error'):
        raise Exception(e)
        callback(False)
    callback(True)


@tornado.gen.engine
def test(a, b):
    data = {'a':a, 'b':b}
    yield tornado.gen.Task(insert, 'huangtao', 'test', data)
    print 'insert data:', data
#     d = yield tornado.gen.Task(find_all, 'huangtao', 'test')
    r = yield tornado.gen.Task(update, 'huangtao', 'test', {'a':a}, {'c': 3})
    print 'update data:', r
    print 'done'

@tornado.gen.engine
def test2():
    spec = {'project_id': 'projectX', 'ver_from': '1.23', 'device_id': 'deviceX'}
    r = yield tornado.gen.Task(find_one, 'huangtao', 'test', spec)
    print 'results =', r
    print 'done'

@tornado.gen.engine
def test3():
    r = yield tornado.gen.Task(distinct, 'fota_test', 'datas', 'ver')
    print 'results =', r
    print 'done'

@tornado.gen.engine
def test4():
    spec = {'device_id': 'fuck_id'}
    r = yield tornado.gen.Task(remove, 'fota_test', 'device', spec)
    print 'results =', r
    print 'done'

@tornado.gen.engine
def test5():
    spec = {'_id': '56fb7d6a1d697d9776b12a2b'}
    fields = {'status': 1}
    r = yield tornado.gen.Task(update, 'fota_test', 'datas', spec, fields)
    print 'results =', r
    print 'done'

if __name__ == '__main__':
    initMongoDb()
    import tornado.ioloop
    io_loop = tornado.ioloop.IOLoop.current()
#     io_loop.call_at(io_loop.time() + 0.1, test, 1, 3)
    io_loop.call_at(io_loop.time(), test5)
#     io_loop.call_at(io_loop.time(), test3)
#     io_loop.call_at(io_loop.time(), test4)
    io_loop.start()



__all__ = [
           initMongoDb,
           insert,
           update,
           find_one,
           find_all,
           distinct,
           remove
           ]
